<?php

namespace app\api\controller\fp;


use app\api\validate\fp\PostLikeValidate;
use app\api\validate\fp\PostValidate;
use app\common\controller\Frontend;
use app\common\enum\fp\PaymentType;
use app\common\enum\fp\PostLikeTypeEnum;
use app\common\enum\fp\PostType;
use app\common\model\User;
use app\logic\es\fp\EsPost;
use app\logic\fp\PostCommentLogic;
use app\logic\fp\PostLikeLogic;
use app\logic\fp\PostLogic;
use app\logic\fp\PostUnlockedLogic;
use app\logic\subscribe\SubscribeLogic;
use app\logic\user\UserLogic;
use Elastic\Elasticsearch\Exception\ClientResponseException;
use Elastic\Elasticsearch\Exception\MissingParameterException;
use Elastic\Elasticsearch\Exception\ServerResponseException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Log;

class Post extends Frontend
{
    protected array $noNeedLogin = [];

    protected array $noNeedPermission = [];

    protected PostLogic $postLogic;

    public function initialize(): void
    {
        parent::initialize();

        $this->postLogic = new PostLogic();

    }

    /**
     * 发布动态
     *
     * 该方法用于处理用户创建动态的请求它首先获取请求参数，然后进行参数验证，
     * 如果验证通过，则将动态信息插入到数据库中最后，它返回一个成功消息
     */
    public function create()
    {
        // 获取POST请求参数
        $checkParam = $params = $this->request->post();
        // 实例化验证器对象，用于后续的参数验证
        $validate = new PostValidate();

        // 使用验证器的创建场景进行参数验证，如果验证失败则抛出异常
        try {
            $checkParam['content'] = htmlspecialchars_decode($params['content']);
            if (!empty($params['title'])) $checkParam['title'] = htmlspecialchars_decode($params['title']);
            $validate->scene('create')->check($checkParam);
        } catch (\Throwable $e) {
            // 如果验证失败，显示错误消息
            $this->error($e->getMessage());
        }

        // 检查是否选择了付费类型，如果没有选择，则抛出异常
        if ($params['payment_type'] > 1 && empty($params['price'])) {
            $this->error(__('please enter a valid price'));
        }

        //检查用户是否是创作者
        if (!UserLogic::checkIsCreator($this->auth->id)) {
            $this->error(__('You are not a creator'));
        }

        // 检查媒体类型
        $extension = [];
        foreach ($params['media_url'] as $media_url) {
            $ext = pathinfo($media_url, PATHINFO_EXTENSION);
            $extension[$ext] = $ext;
        }
        // 判断是否选择了两种以上的媒体类型
        if (count($extension) > 1) {
            $this->error(__('Please select only one type of media'));
        }

        //判的媒体类型是否正确
        if (image_or_video_extension($params['media_url'][0]) != $params['media_type']) {
            $this->error(__('Please select the correct type of media'));
        }

        //免费的就不能是会员才能解锁字段
        if ($params['payment_type'] == PaymentType::FREE->value) {
            $params['is_vip_unlock'] = 0;
        }

        // 准备要插入数据库的数据
        $data = [
            'title' => $params['title'] ?? '',
            'type' => $params['type'] ?? 0,
            'user_id' => $this->auth->id,
            'content' => $params['content'],
            'payment_type' => $params['payment_type'],
            'price' => $params['price'] ?? 0,
            'media_type' => $params['media_type'],
            'media_url' => $params['media_url'],
            'is_vip_unlock' => $params['is_vip_unlock'],
        ];
        try {
            $res = $this->postLogic->insert($data);
        } catch (\Throwable $e) {
            $this->error(__('Publish failed'));
        }

        // 返回成功发布动态的消息
        $this->success(__('Publish success'), $res);
    }

    /**
     * 获取不同类型的动态列表
     *
     * 本函数根据用户请求的类型，返回相应的帖子列表数据
     * 它通过查询字符串参数来确定列表类型，并根据用户的身份获取个性化列表
     */
    public function lists()
    {
        // 获取请求中的查询条件
        $type = $this->request->param('type');
        $page = $this->request->param('page');
        $size = (int)$this->request->param('size');
        $size = $size ?: 15;
        $page = $page ?: 1;
        // 初始化查询参数，包括当前用户ID和分页信息
        $params['auth_user_id'] = $this->auth->id;

        if ($size > 15 || $size < 0) {
            $size = 15;
        }
        $params['size'] = $size;
        $params['from'] = ($page - 1) * $params['size'];
        $params['filter'] = [
            ['term' => ['type' => PostType::Normal->value]]
        ];
        // 根据类型调用不同的逻辑方法来获取数据
        try {
            $result = match ($type) {
                "follow" => $this->postLogic->follow($params),
                "subscribe" => $this->postLogic->subscribe($params),
                "video" => $this->postLogic->video($params),
                "like" => $this->postLogic->like($params),
                "unlocked" => $this->postLogic->unlock($params),
                "vip" => $this->postLogic->vip($params),
                default => $this->postLogic->all($params),
            };

            $result['list'] = array_map(function ($item) {
                $item['is_like'] = PostLikeLogic::getInstance()->isLike($item['id'], $this->auth->id);
                $item['is_subscribe'] = SubscribeLogic::getInstance()->isSubscribe($item['user_id'], $this->auth->id);
                if (!$item['is_subscribe']) {
                    $item['is_unlocked'] = PostUnlockedLogic::getInstance()->isUnlockedByUser($this->auth->id, $item['id']);
                } else {
                    $item['is_unlocked'] = true;
                }
                if ($item['payment_type'] == PaymentType::FREE->value) {
                    $item['is_unlocked'] = true;
                }

                $item['like_count'] = PostLikeLogic::getInstance()->getLikeCount($item['id'], $item['user_id']);
                $item['comment_count'] = PostCommentLogic::getInstance()->getCommentCount($item['id']);
                $item['tips'] = UserLogic::getInstance()->tips($item['user_id']);
                $user = User::initModel()->where('id', $item['user_id'])->field('is_creator,avatar, vip, vip_expire')->find()->toArray();
                if ($user['vip_expire'] < time()) {
                    $user['vip'] = 0;
                }
                unset($user['vip_expire']);
                $item['user'] = array_merge($user, $item['user']);
                $item['user']['is_creator'] = (int)$user['is_creator'];

                $unlocked = $item['is_unlocked'] || $item['is_subscribe'] || $item['user_id'] == $this->auth->id;
                $item['media'] = PostLogic::getInstance()->mediaSignUrl($item['media'], $unlocked);

                $item['content'] =  nl2br(htmlspecialchars($item['content'], ENT_QUOTES), false);

                return $item;
            }, $result['list']);


        } catch (\RuntimeException $e) {
            $this->error($e->getMessage());
        } catch (ClientResponseException $e) {
            if ($e->getCode() === 404) {
                $this->error(__('no data'));
            }
            $this->error($e->getMessage());
        } catch (\Throwable $exception) {
            Log::channel('my')->error($exception->getMessage() . PHP_EOL . $exception->getTraceAsString());
            // 如果发生异常，捕获并显示错误信息
            $this->error(__('server error'));
        }

        // 查询成功后，调用成功方法处理查询结果
        $this->success('', $result);
    }


    /**
     * 执行搜索操作
     *
     * 该方法负责处理搜索请求，获取请求参数，设置搜索参数，并调用逻辑层进行搜索
     * 它处理的参数包括 'query'（搜索查询）、'page'（页码）和 'type'（搜索类型）
     * 此外，它还涉及用户身份验证，通过 $this->auth->id 获取当前用户ID
     */
    public function search()
    {
        try {
            // 获取搜索请求参数
            $params = $this->request->param(['query', 'page', "type"]);
            $page = $params['page'] ? (int)$params['page'] : 1;
            $size = (int)$this->request->param('size');
            $size = $size ?: 15;

            if ($size > 15 || $size < 0) {
                $size = 15;
            }
            $params['size'] = $size;
            // 计算搜索结果的起始位置
            $params['from'] = ($page - 1) * $params['size'];
            // 移除 'page' 参数，因为它已经不再需要
            unset($params['page']);

            // 添加当前用户ID到搜索参数中，以便进行权限控制
            $params['auth_user_id'] = $this->auth->id;
            $params['filter'] = [
                ['term' => ['type' => PostType::Normal->value]]
            ];
            // 执行搜索
            $response = $this->postLogic->search($params);

            $response['list'] = array_map(function ($item) {
                $item['is_like'] = PostLikeLogic::getInstance()->isLike($item['id'], $this->auth->id);
                $item['is_subscribe'] = SubscribeLogic::getInstance()->isSubscribe($item['user_id'], $this->auth->id);
                if (!$item['is_subscribe']) {
                    $item['is_unlocked'] = PostUnlockedLogic::getInstance()->isUnlockedByPost($this->auth->id, $item['id']);
                } else {
                    $item['is_unlocked'] = true;
                }
                if ($item['payment_type'] == PaymentType::FREE->value) {
                    $item['is_unlocked'] = true;
                }

                $item['like_count'] = PostLikeLogic::getInstance()->getLikeCount($item['id'], $item['user_id']);
                $item['comment_count'] = PostCommentLogic::getInstance()->getCommentCount($item['id']);
                $item['tips'] = UserLogic::getInstance()->tips($item['user_id']);
                $user = User::initModel()->where('id', $item['user_id'])->field('is_creator,avatar, vip, vip_expire')->find()->toArray();
                if ($user['vip_expire'] < time()) {
                    $user['vip'] = 0;
                }
                unset($user['vip_expire']);
                $item['user'] = array_merge($user, $item['user']);
                $item['user']['is_creator'] = (int)$user['is_creator'];

                $unlocked = $item['payment_type'] == PaymentType::FREE->value || $item['is_unlocked'] || $item['is_subscribe'] || $item['user_id'] == $this->auth->id;
                $item['media'] = PostLogic::getInstance()->mediaSignUrl($item['media'], $unlocked);
                $item['content'] =  nl2br(htmlspecialchars($item['content'], ENT_QUOTES), false);
                return $item;
            }, $response['list']);
        } catch (\RuntimeException $e) {
            $this->error($e->getMessage());
        } catch (ClientResponseException $e) {
            if ($e->getCode() === 404) {
                $this->error(__('No results found'));
            }
            $this->error($e->getMessage());
        } catch (\Throwable $e) {
            Log::channel('my')->error($e->getMessage() . PHP_EOL . $e->getTraceAsString());
            $this->error(__('server error'));
        }

        // 搜索成功，返回成功信息和搜索结果
        $this->success(__('success'), $response);
    }


    /**
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \Throwable
     */
    public function like()
    {
        // 获取请求参数
        $params = $this->request->param(['post_id', 'user_id', 'type']);

        // 实例化验证器对象，用于后续的参数验证
        $validate = new PostLikeValidate();

        // 使用验证器的创建场景进行参数验证，如果验证失败则抛出异常
        try {
            $validate->scene('like')->check($params);
        } catch (\Throwable $e) {
            // 如果验证失败，显示错误消息
            $this->error($e->getMessage());
        }

        $postModel = \app\common\model\fp\Post::initModel($params['user_id']);
        $post = $postModel->where(['user_id' => $params['user_id'], 'id' => $params['post_id']])->find();
        if (!$post) {
            $this->error(__('Record not found'));
        }

        try {
            PostLikeLogic::getInstance()->like($post, $params['type'], $this->auth->id);
        } catch (\Throwable $e) {
            Log::channel('my')->error($e->getMessage() . PHP_EOL . $e->getTraceAsString());
            $this->error(__('failed'));
        }

        if (PostLikeTypeEnum::from($params['type']) === PostLikeTypeEnum::CANCEL) {
            $this->success(__('Like cancel'));
        }
        if (PostLikeTypeEnum::from($params['type']) === PostLikeTypeEnum::LIKE) {
            $this->success(__('Like success'));
        }
    }

    public function info()
    {
        $params = $this->request->param(['post_id', 'user_id']);

        $validate = new PostValidate();

        try {
            $validate->scene('info')->check($params);
        } catch (\Throwable $e) {
            $this->error($e->getMessage());
        }

        try {
            $post = EsPost::getInstance()->get($params['post_id']);
        } catch (ClientResponseException $e) {
            $this->error(__('Record not found'));
        } catch (MissingParameterException $e) {
        } catch (ServerResponseException $e) {
        }

        if (!$post){
            $this->error(__('Record not found'));
        }
        $esData = $post->asArray();

        $post = $esData['_source'] ?? [];
        $post['is_like'] = PostLikeLogic::getInstance()->isLike($post['id'], $this->auth->id);
        $post['is_subscribe'] = SubscribeLogic::getInstance()->isSubscribe($post['user_id'], $this->auth->id);
        if (!$post['is_subscribe']) {
            $post['is_unlocked'] = PostUnlockedLogic::getInstance()->isUnlockedByPost($this->auth->id, $post['id']);
        } else {
            $post['is_unlocked'] = true;
        }
        if ($post['payment_type'] == PaymentType::FREE->value) {
            $post['is_unlocked'] = true;
        }

        $post['like_count'] = PostLikeLogic::getInstance()->getLikeCount($post['id'], $post['user_id']);
        $post['comment_count'] = PostCommentLogic::getInstance()->getCommentCount($post['id']);
        $post['tips'] = UserLogic::getInstance()->tips($post['user_id']);
        $post['user'] = User::initModel()->where('id', $post['user_id'])->field('id, nickname, motto, is_creator,avatar, vip, vip_expire')->find()->toArray();
        if ($post['user']['vip_expire'] < time()) {
            $post['user']['vip'] = 0;
        }
        unset($post['user']['vip_expire']);
        $unlocked =  $post['is_unlocked'] || $post['is_subscribe'] || $post['user_id'] == $this->auth->id;
        $post['media'] = PostLogic::getInstance()->mediaSignUrl($post['media'], $unlocked);
        $post['content'] =  nl2br(htmlspecialchars($post['content'], ENT_QUOTES), false);
        $this->success(__('success'), $post);
    }

    /**
     * 获取最新的用户帖子
     */
    public function userLastPost()
    {
        $params = $this->request->param(['user_id']);

        $validate = new PostValidate();

        try {
            $validate->scene('userLastPost')->check($params);
        } catch (\Throwable $e) {
            $this->error($e->getMessage());
        }

        try {
            $post = PostLogic::getInstance()->getUserLastPost((string)$params['user_id'], $this->auth->id);
        } catch (\Throwable $e) {
            $this->error(__('Server error'));
        }

        $this->success(__('success'), $post);

    }

    public function unlock()
    {
        $params = $this->request->param(['post_id', 'creator_id']);

        $validate = new PostValidate();

        try {
            $validate->scene('unlock')->check($params);
        } catch (\Throwable $e) {
            $this->error($e->getMessage());
        }

        try {
            $post = PostUnlockedLogic::getInstance()->unlock($params['creator_id'], $params['post_id'], $this->auth->id);
        } catch (\Throwable $e) {
            $message = config('app.env') != 'prod' ? $e->getMessage() : __('Server error');
            $this->error($message);
       }
        $this->success(__('success'), $post);
    }
}